package com.fast.fast.upms.biz.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fast.fast.common.base.exception.BizException;
import com.fast.fast.upms.api.entity.*;
import com.fast.fast.upms.api.vo.SysTenantVO;
import com.fast.fast.upms.biz.base.util.ClearAuthUtils;
import com.fast.fast.upms.biz.base.util.TreeUtils;
import com.fast.fast.upms.biz.mapper.SysTenantMapper;
import com.fast.fast.upms.biz.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lyf
 * @description 针对表【sys_tenant(系统租户表)】的数据库操作Service实现
 * @createDate 2022/01/01 00:00 周六
 */
@Service
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant>
        implements SysTenantService {

    @Value("${tenant.open:false}")
    private boolean tenantOpen;

    @Autowired
    private SysDeptService sysDeptService;

    @Autowired
    private SysPostService sysPostService;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysPermService sysPermService;

    @Autowired
    private SysUserPostService sysUserPostService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRolePermService sysRolePermService;

    @Autowired
    private ClearAuthUtils clearAuthUtils;

    /**
     * 除admin角色外的默认角色权限列表映射
     */
    private final Map<String, List<String>> EXTRA_ROLE_PERMS_MAP = new HashMap<String, List<String>>() {
        {
            put("客服", Arrays.asList("我的博客"));
            put("部门主管", Arrays.asList("我的博客"));
        }
    };

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean delete(List<Long> ids) {
        if (Long.parseLong(StpUtil.getLoginId().toString()) != 1) {
            throw new BizException("非法操作");
        }
        removeBatchByIds(ids);
        // 忽略租户，获取当前数据库中所有的表名
        List<String> tableNames = baseMapper.listDBTableNames().stream().filter(o -> !"sys_tenant".equals(o)).collect(Collectors.toList());
        ids.forEach(tenantId -> {
            // 忽略租户，为该租户删除所有数据
            baseMapper.removeAllDataForTenantId(tableNames, tenantId);
        });
        return true;
    }

    @Override

    public List<SysTenantVO> listTenants() {
        List<SysTenantVO> sysTenantsVOs = list().stream().map(o -> {
            SysTenantVO sysTenantVO = BeanUtil.copyProperties(o, SysTenantVO.class);
            sysTenantVO.setValue(o.getId());
            return sysTenantVO;
        }).collect(Collectors.toList());
        return sysTenantsVOs;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean initNewTenantDBDataByUserIdAndTenantId(Long userId, Long tenantId) {
        if (!tenantOpen) {
            return true;
        }
        if (Long.parseLong(StpUtil.getLoginId().toString()) != 1) {
            throw new BizException("非法操作，非法用户正在初始化新租户数据库数据");
        }
        if (ObjUtil.isEmpty(userId)) {
            throw new BizException("非法操作，用户id不能为空");
        }
        if (ObjUtil.isEmpty(tenantId)) {
            throw new BizException("非法操作，租户id不能为空");
        }
        if (tenantId == 1) {
            return true;
        }

        // ****************************************************部门表**************************************************** //
        // 获取部门表数据列表
        List<SysDept> sysDepts = sysDeptService.list(Wrappers.lambdaQuery(SysDept.class));
        // 获取包括所有子节点信息的父节点
        List<SysDept> sysDeptsNodes = sysDepts.stream().filter(o -> o.getPid() == 0)
                .map(o -> TreeUtils.listNodes(sysDepts, o))
                .collect(Collectors.toList());
        // 处理并新增部门表数据
        sysDeptsNodes.forEach(o -> {
            this.handleAndSaveForSysDept(o, tenantId);
        });

        // ****************************************************岗位表**************************************************** //
        // 获取岗位表数据列表
        List<SysPost> sysPosts = sysPostService.list(Wrappers.lambdaQuery(SysPost.class));
        // 为该租户批量新增岗位表数据
        List<SysPost> newSysPosts = sysPosts.stream().map(o -> {
            SysPost sysPost = BeanUtil.copyProperties(o, SysPost.class, "id", "version", "createBy", "createTime", "updateBy", "updateTime");
            sysPost.setTenantId(tenantId);
            return sysPost;
        }).collect(Collectors.toList());
        sysPostService.saveBatch(newSysPosts);

        // ****************************************************角色表**************************************************** //
        // 获取角色表数据列表
        List<SysRole> sysRoles = sysRoleService.list(Wrappers.lambdaQuery(SysRole.class));
        // 为该租户批量新增角色表数据
        List<SysRole> newSysRoles = sysRoles.stream().map(o -> {
            SysRole sysRole = BeanUtil.copyProperties(o, SysRole.class, "id", "version", "createBy", "createTime", "updateBy", "updateTime");
            sysRole.setTenantId(tenantId);
            return sysRole;
        }).collect(Collectors.toList());
        sysRoleService.saveBatch(newSysRoles);

        // ****************************************************权限表**************************************************** //
        // 获取权限表数据列表
        List<SysPerm> sysPerms = sysPermService.list(Wrappers.lambdaQuery(SysPerm.class));
        // 获取包括所有子节点信息的父节点
        List<SysPerm> newSysPerms = new ArrayList<>();
        List<SysPerm> sysPermsNodes = sysPerms.stream().filter(o -> o.getPid() == 0)
                .map(o -> TreeUtils.listNodes(sysPerms, o))
                .collect(Collectors.toList());
        // 处理并新增权限表数据
        sysPermsNodes.forEach(o -> {
            this.handleAndSaveForSysPerm(o, tenantId, newSysPerms);
        });

        // ****************************************************用户岗位中间表**************************************************** //
        // 为该租户新增用户岗位中间表数据
        if (ObjUtil.isNotEmpty(newSysPosts)) {
            SysUserPost sysUserPost = new SysUserPost();
            sysUserPost.setTenantId(tenantId);
            sysUserPost.setUserId(userId);
            sysUserPost.setPostId(newSysPosts.get(0).getId());
            sysUserPostService.save(sysUserPost);
        }

        // ****************************************************用户角色中间表**************************************************** //
        // 为该租户新增用户角色中间表数据
        if (ObjUtil.isNotEmpty(newSysRoles)) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setTenantId(tenantId);
            sysUserRole.setUserId(userId);
            sysUserRole.setRoleId(newSysRoles.get(0).getId());
            sysUserRoleService.save(sysUserRole);
        }

        // ****************************************************角色权限中间表**************************************************** //
        // 为该租户批量新增角色权限中间表数据
        if (ObjUtil.isNotEmpty(newSysPerms)) {
            // 租户管理员的默认权限
            List<SysRolePerm> newSysRolePerms = newSysPerms.stream().map(o -> {
                SysRolePerm sysRolePerm = new SysRolePerm();
                sysRolePerm.setTenantId(tenantId);
                sysRolePerm.setRoleId(newSysRoles.get(0).getId());
                sysRolePerm.setPermId(o.getId());
                return sysRolePerm;
            }).collect(Collectors.toList());

            // 除admin角色外的默认权限
            List<SysRolePerm> extraRolePerms = new ArrayList<>();
            EXTRA_ROLE_PERMS_MAP.forEach((k, v) -> {
                SysRole sysRole = newSysRoles.stream().filter(o -> k.equals(o.getName())).findFirst().orElse(null);
                if (sysRole != null) {
                    List<SysRolePerm> collect = newSysPerms.stream()
                            .filter(o -> v.contains(o.getName()))
                            .map(o -> {
                                SysRolePerm sysRolePerm = new SysRolePerm();
                                sysRolePerm.setTenantId(tenantId);
                                sysRolePerm.setRoleId(sysRole.getId());
                                sysRolePerm.setPermId(o.getId());
                                return sysRolePerm;
                            })
                            .collect(Collectors.toList());
                    extraRolePerms.addAll(collect);
                }
            });

            sysRolePermService.saveBatch(newSysRolePerms);
            sysRolePermService.saveBatch(extraRolePerms);
        }

        // 清除指定用户的登录信息
        clearAuthUtils.clearSpecifiedUserLoginInfo(Collections.singletonList(userId));
        return true;
    }

    /**
     * 处理并新增部门表数据
     *
     * @param sysDept
     * @param tenantId
     */
    private void handleAndSaveForSysDept(SysDept sysDept, Long tenantId) {
        sysDept.setId(null);
        sysDept.setVersion(null);
        sysDept.setCreateBy(null);
        sysDept.setCreateTime(null);
        sysDept.setUpdateBy(null);
        sysDept.setUpdateTime(null);
        sysDept.setTenantId(tenantId);
        sysDeptService.save(sysDept);

        List<SysDept> children = sysDept.getChildren();
        if (ObjUtil.isNotEmpty(children)) {
            children.forEach(o -> {
                o.setId(null);
                o.setPid(sysDept.getId());
                handleAndSaveForSysDept(o, tenantId);
            });
        }
    }

    /**
     * 处理并新增权限表数据
     *
     * @param sysPerm
     * @param tenantId
     */
    private void handleAndSaveForSysPerm(SysPerm sysPerm, Long tenantId, List<SysPerm> newSysPerms) {
        sysPerm.setId(null);
        sysPerm.setVersion(null);
        sysPerm.setCreateBy(null);
        sysPerm.setCreateTime(null);
        sysPerm.setUpdateBy(null);
        sysPerm.setUpdateTime(null);
        sysPerm.setTenantId(tenantId);
        sysPermService.save(sysPerm);
        newSysPerms.add(sysPerm);

        List<SysPerm> children = sysPerm.getChildren();
        if (ObjUtil.isNotEmpty(children)) {
            children.forEach(o -> {
                o.setId(null);
                o.setPid(sysPerm.getId());
                handleAndSaveForSysPerm(o, tenantId, newSysPerms);
            });
        }
    }

}




